﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Globalization;

using Domain.Core.Specification;

using Domain.MainModule.Customers;
using Domain.MainModule.Entities;

using Infraestructure.CrossCutting.Logging;
using Infraestructure.Data.Core;
using Infraestructure.Data.Core.Extensions;
using Infraestructure.Data.MainModule.Resources;
using Infraestructure.Data.MainModule.UnitOfWork;
using System.Data.Objects;

namespace Infraestructure.Data.MainModule.Repositories
{
    public class CustomerRepository: CustomRepository<Customer, User>, ICustomerRepository
    {

        #region constructor

        /// <summary>
        /// Default constructor
        /// </summary>
        /// <param name="unitOfWork">IMainModuleUnitOfWork dependency, intented to be resolved with IoC</param>
        /// <param name="traceManager">ITraceManager context, intended to be resolved wiht IoC</param>
        public CustomerRepository(IMainModuleUnitOfWork unitOfWork, ITraceManager traceManager) : base(unitOfWork, traceManager) { }

        #endregion Constructor

        #region private methods

        private Customer FindCustomerBySpecification(ISpecification<Customer> specification)
        {
            //validate specification
            if (specification == (ISpecification<Customer>)null)
            {
                throw new ArgumentNullException("specification");
            }

            IMainModuleUnitOfWork context = this.UnitOfWork as IMainModuleUnitOfWork;

            if (context != null)
            {
                //perform operation in this repository
                IQueryable<Customer> customers = context.Users.Where(u => u is Customer).OfType<Customer>();
                return customers
                    .Include("Country")
                    .Include("Gender")
                    .Where(specification.SatisfiedBy()).SingleOrDefault();
            }
            else
            {
                throw new InvalidOperationException(string.Format(
                                                                   CultureInfo.InvariantCulture,
                                                                   Messages.exception_InvalidStoreContext,
                                                                   this.GetType().Name));
            }
        }

        #endregion


        #region ICustomerRepository implementations

        public Customer FindCustomer(ISpecification<Customer> specification)
        {
            //validate specification
            if (specification == (ISpecification<Address>)null)
            {
                throw new ArgumentNullException("specification");
            } 
            
            return this.FindCustomerBySpecification(specification);
        }

        public IEnumerable<Customer> GetPagedCustomers(int pageIndex, int pageCount)
        {
            //checking arguments for this query 
            if (pageIndex < 0)
                throw new ArgumentException(Resources.Messages.exception_InvalidPageIndex, "pageIndex");

            if (pageCount <= 0)

                throw new ArgumentException(Resources.Messages.exception_InvalidPageCount, "pageCount");

            IMainModuleUnitOfWork context = this.UnitOfWork as IMainModuleUnitOfWork;
            if (context != null)
            {
                //perform operation in this repository
                IQueryable<Customer> customers = context.Users
                                                .Include("Country")
                                                .Include("Gender")
                                                .Where(u => u is Customer).OfType<Customer>();
                return customers
                    .OrderBy(c=> c.UserId)
                    .Skip(pageIndex * pageCount)
                    .Take(pageCount);
            }
            else
            {
                throw new InvalidOperationException(string.Format(
                                                                   CultureInfo.InvariantCulture,
                                                                   Messages.exception_InvalidStoreContext,
                                                                   this.GetType().Name));
            }

        }


        #endregion
    }
}
